#! python3
##############################################################################
#
# andy6thvoice.py $Rev:$
# $Id$
#
# Copyright (c) 2012, shimoda as kuri65536 _dot_ hot mail _dot_ com
#                     ( email address: convert _dot_ to . and joint string )
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted
# provided that the following conditions are met:
#
# - Redistributions of source code must retain the above copyright notice,
#   this list of conditions and
#   the following disclaimer.
# - Redistributions in binary form must reproduce the above copyright notice,
#   this list of conditions
#   and the following disclaimer in the documentation and/or other materials
#   provided with the
#   distribution.
# - Neither the name of the <ORGANIZATION> nor the names of its contributors
#   may be used to endorse or
#   promote products derived from this software without specific prior
#   written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
# OF MERCHANTABILITY AND
# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT HOLDER OR
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
# EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER
# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT
# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
##############################################################################
import sys
import time
import json
import android
from threading import Thread
from Queue import Queue, Empty


# commands                          # {{{1
_fowardGo = "motor=170"
_fowardStop = "motor=0"
_fowardSpeedup = "motor=+30"
_fowardSpeeddown = "motor=-30"
_backwardGo = "motor=-170"
_laugh = "misc=100"
_end = "end=0"
_yes = "gauge=200"
_no = "gauge=0"

words = (                           # {{{1
    ("聞こえてる", _yes),

    ("いいおとこ", _laugh),
    ("いい男", _laugh),
    ("かっこいい", _laugh),

    ("ゆっくり", _fowardSpeeddown),

    ("格好いい", _laugh),
    ("あそぼ", _laugh),
    ("遊ぼ", _laugh),
    ("あそぶ", _laugh),
    ("遊ぶ", _laugh),

    ("終わり", _end),
    ("終り", _end),
    ("おわり", _end),

    ("悲しい", _no),
    ("元気", _yes),

    ("ストップ", _fowardStop),
    ("止まれ", _fowardStop),
    ("とまれ", _fowardStop),

    ("うしろ", _backwardGo),
    ("後", _backwardGo),

    ("早く", _fowardSpeedup),
    ("はやく", _fowardSpeedup),

    ("進め", _fowardGo),
    ("stop", _fowardGo),

    ("いって", _fowardGo),
    ("前", _fowardGo),
    ("まえ", _fowardGo),
    ("go", _fowardGo),

    ("back", _backwardGo),
)


class Andy6CtrlLayout(object):      # {{{1
    def __init__(self, uuid):       # {{{1
        self.motor = 0
        self.led = 0
        self.gauge = 0
        self.uuid = uuid
        self.tbase = time.time()

    def onQuit(self, view, event):
        app.exit_FullScreenWrapper2App()
        droid.usbserialWrite("F000F000", uuid)      # stop to contorl

    def operation(self, motor=None, led=None, gauge=None, misc=None):   # {{{1
        # 1st, set motor speed.
        if motor is None:
            motor = self.motor
        if motor < 0:
            if motor < -255:
                motor = -255
            ret = "B%03d" % (-motor)
        else:
            if motor > 255:
                motor = 255
            ret = "F%03d" % motor
        self.motor = motor

        # 2nd, set various equipments.
        if led is not None:
            self.led = led = led % 256          # limit and force positive
            ret += "F%03d" % led
        elif gauge is not None:
            self.gauge = gauge = gauge % 256    # limit and force positive
            ret += "B%03d" % gauge
        elif misc is not None:
            if misc:
                ret += "S255"
            else:
                ret += "S000"
            self.misc = not (not misc)
        else:
            ret += "B%03d" % self.gauge

        if droid.usbserialReadReady(uuid).result:
            buf = droid.usbserialRead(uuid)
            print("Received: ", buf)

        t = time.time()
        if t - self.tbase > 0.3:
            print("send bytes...", ret)
            self.tbase = t
            droid.usbserialWrite(ret, uuid)
        return ret


def connect():     #{{{1
    h = None
    for k, v in droid.usbserialGetDeviceList().result.items():
        print(k, v)
        if '"0409","FFFD"' in v:
            # v is '["device-name","VID","PID","hashCode"]'
            h = json.loads(v)[-1]
            print("device was found, try to connect =>", h)
    if h is None:
        print("device was not found")
        return False

    ret = droid.usbserialConnect(h, 'trg78k')
    if not "OK" in ret.result:
        print("can't connect to device: ", ret.result)
        return False
    uuid = json.loads(ret.result)[-1]
    print("connected with ", h, uuid)

    # wait until the permission be allowed by user.
    n = 10
    while n > 0 and not droid.usbserialReadReady(uuid).result:
        n -= 1
        print("waiting for connect....", n)
        time.sleep(1)

    if n <= 0:
        print("??? can't receive start byte ???")
        return False
    return uuid


def voicethread():                  # {{{1
    global q
    droid2 = android.Android()
    while True:
        ret = droid2.recognizeSpeech()
        if ret.result is None:
            print("voicethread: recognizeSpeech error.")
            continue
        msg = ret.result
        for word, func in words:
            if msg != word:
                continue
            if func == _end:
                q.put(_end)
                return
            print("voicethread: rec: ", msg)
            q.put(func)
            break
        else:
            print("voicethread: not in keywords: ", msg)


def main(uuid):                     # {{{1
    global q
    q = Queue()
    thd = Thread(target=voicethread, name="voice")
    thd.start()

    ctrl = Andy6CtrlLayout(uuid)
    while True:
        time.sleep(0.1)
        try:
            func = q.get(False)
        except Empty:
            continue
        if func == _end:
            break
        func = func.split("=")
        if len(func) != 2:
            continue
        l, r = func
        if r.startswith("+") or r.startswith("-"):
            r = getattr(ctrl, l) + int(r)
        r = int(r)
        if l == "motor":
            if abs(ctrl.motor) < 100:
                ctrl.operation(motor=255)
                time.sleep(2)
        print("%s => %d" % (l, r))
        ctrl.operation(**{l: r})


if __name__ == '__main__':          # {{{1
    droid = android.Android()
    uuid = connect()
    if 1 and not uuid:
        droid.makeToast("can't connect to USB Serial!")
        sys.exit(0)
    main(uuid)

# vi: ft=python:ts=4:et:fdm=marker
